<?php
namespace app\common\controller;
use think\Db;
use Exception;
use Email\Email;
use Process\RedisClient;

class EmailWork extends \app\common\controller\Base
{
    protected $model ;

    protected $exec_num = 50 ;

    protected $redis_client ;

    protected $mail_obj ;

    protected $setting ;

    protected $allow_error_times = 30;

    /**
     * EMAIL
     */
    public function queueWork()
    {
        try{
            $this->baseInt();
            $setting = $this->redis_client->HGETALL(EMAIL_CONF_TYPE);
            if(!$setting)// 取不到配置不执行;
            {
                $this->fileLog('邮件数队列任务进程:没有获取到redis存储的配置信息!,redis_error:'.$this->redis_client->getLastError().",行数：".__LINE__.",方法：".__METHOD__);
                sleep(1);
                goto end ;
            }
            // 更新发送对象
            foreach ($setting as $k => $v)
            {
                if (empty($this->mail_obj[$k]) || $this->mail_obj[$k]->setting != $v)
                {
                    $this->mail_obj[$k]          = new Email(json_decode($v, true));
                    $this->mail_obj[$k]->setting = $v;
                }
            }
            if($this->setting)
            {
                $expire_time = array_diff($this->setting, $setting);
                foreach ($expire_time as $k => $v) {
                    unset($this->mail_obj[$k]);
                }
            }
            $this->setting = $setting ;
            unset($v, $k,$setting,$expire_time);
            if(empty($this->model['email_list']))
            {
                $this->model['email_list'] = Db::name('email_list');
            }
            //格式化获取模板
            $template = $this->redis_client->hGetAll(EMAIL_TEMPLATE);
            if(!$template)
            {
                throw new Exception('【邮件送队列】获取短信模板失败, '.$this->redis_client->getlasterror());
            }
            foreach($template as $k=>$v)
            {
                $template[$k] = json_decode($v,true);
            }
            $i = 0 ;
            do
            {
                $email = $this->redis_client->Pop(EMAIL_QUEUE);
                #$email = '{"api_time":1518334286,"request_client":"系统","template":"1","sign":"系统通知","to":"feng.yaqing@jiurong.com,echomiao@foxmail.com,793085352@qq.com","var_title":"","var_content":["ChuangLan","hangye","jiurong",92677,"2018-02-11"],"add_time":1518334286}';
                if($email)
                {
                    $data = json_decode($email,true);
                    if($data)
                    {
                        // 处理内容
                        if($template[$data['template']]['var_content'])
                        {
                            $data['content'] = preg_replace($template[$data['template']]['var_content'],$data['var_content'],$template[$data['template']]['content']);
                        }
                        else
                        {
                            $data['content'] = $template[$data['template']]['content'] ;
                        }
                        // 处理标题
                        if($template[$data['template']]['var_title'])
                        {
                            $data['title'] = preg_replace($template[$data['template']]['var_title'],$data['var_title'],$template[$data['template']]['title']);
                        }
                        else
                        {
                            $data['title'] = $template[$data['template']]['title'] ;
                        }
                        if($this->debug)
                        {
                            $res = [
                                'channel'=>'test_account',
                                'reply_to'=>'test',
                                'send_time'=>time(),
                                'accept_time'=>time(),
                                'status'=>2,
                                'status_info'=>'debug 模式不会发送邮件',
                            ];
                        }
                        else
                        {
                            $res = $this->send($data);
                        }
                        $to_arr = explode(',', $data['to']);
                        foreach($to_arr as $k=>$v)
                        {
                            $this->redis_client->Push('email_list', json_encode([
                                'request_client' => $data['request_client'],
                                'api_time'       => $data['api_time'],
                                'add_time'       => $data['add_time'],
                                'var_content'    => $data['var_content']?json_encode($data['var_content'],JSON_UNESCAPED_UNICODE):'',
                                'var_title'      => $data['var_title']?json_encode($data['var_title'],JSON_UNESCAPED_UNICODE):'',
                                'template_id'    => $data['template'],
                                'sign'           => $data['sign'],
                                'channel'        => $res['channel'],
                                'send_time'      => $res['send_time'],
                                'accept_time'    => $res['accept_time'],
                                'status'         => $res['status'],
                                'status_info'    => $res['status_info'],
                                'to'             => $v,
                            ], JSON_UNESCAPED_UNICODE));
                        }
                    }
                    $this->redis_client->dealer(EMAIL_QUEUE,$email);
                }
                $i++ ;
            }
            while($email && $i< $this->exec_num);
        }
        catch (Exception $e)
        {
            $error_string = sprintf("error:%s,code:%s,method：%s,line:%d,file stat:%s,trace:%s,",$e->getMessage(),$e->getCode(),__METHOD__,$e->getLine(),$e->getFile(),$e->getTraceAsString());
            $this->fileLog($error_string);
        }
        end:
    }

    public function dbSave()
    {
        try{
            if(!$this->redis_client)
            {
                $this->redis_client = new RedisClient($this->redis_conf);
            }
            if(empty($this->model['email_list']))
            {
                $this->model['email_list'] = Db::name('email_list');
            }
            // 每次入五百
            $num = 500;
            // 邮件
            $res = $this->redis_client->lRange('email_list',-$num,-1);
            if($res)
            {
                foreach ($res as $k=>$v)
                {
                    $res[$k] = json_decode($v,true);
                    $res[$k]['insert_time'] = time();
                }
                if($this->model['email_list']->insertAll($res))
                {
                    if(!$this->redis_client->ltrim('email_list',0,-($num+1))) $this->fileLog("【删除已经入库的redis数据】失败!".sprintf("method：%s,line:%d,file stat:%s",__METHOD__,__LINE__,__FILE__)) ;;
                }
            }
        } catch (Exception $e)
        {
            $error_string = sprintf("error:%s,code:%s,method：%s,line:%d,file stat:%s,trace:%s,",$e->getMessage(),$e->getCode(),__METHOD__,$e->getLine(),$e->getFile(),$e->getTraceAsString());
            $this->fileLog($error_string);
            return ;
        }
    }

    /**
     * @param $data
     * @return array
     */
    protected function send($data)
    {
        $return = ['send_time'=>time()];
        $date = date('Y-m-d');
        do{
            $obj = current($this->mail_obj) ;
            if(empty($obj->error_times) || $obj->error_times < $this->allow_error_times)
            {
                $res = $obj->send($data['to'],$data['title'],$data['content'],$data['sign']);
                if($res)
                {
                    $return['status'] = 2 ;
                    $return['status_info'][] = $res ;
                    $return['channel'] = '';
                    $return['reply_to'] = '';
                    if($obj->date == $date)
                    {
                        $obj->error_times += 1 ;
                    }
                    else
                    {
                        $obj->error_times += 1 ;
                        $obj->date =  $date ;
                    }
                }
                else
                {
                    $return['status'] = 1 ;
                    $return['status_info'][] = '发送成功';
                    $return['reply_to'] = json_encode($obj->config['reply_to'],JSON_UNESCAPED_UNICODE);
                    $return['channel'] = $obj->setting;
                }
                $return['accept_time'] = time();
            }
            else
            {
                $return['status'] = 3 ;
                $return['status_info'][] = $obj->setting.'当前邮件发送账号错误超限';
                $return['accept_time'] = 0;
                $return['channel'] = '';
                $return['reply_to'] = '';
            }
        }
        while(next($this->model));
        $return['status_info'] = json_encode($return['status_info'],JSON_UNESCAPED_UNICODE);
        return $return ;
    }

    /**
     * @throws Exception
     */
    protected function baseInt()
    {
        if(!$this->redis_client)
        {
            $this->redis_client = new RedisClient($this->redis_conf);
        }
    }


    /**
     * 记录运行错误日志
     * @param $error_string
     */
    public function fileLog($error_string)
    {
        $error_file = dirname(dirname(dirname(__DIR__))).'/runtime/mobile/log/mail_error.log';
        if(!is_dir(dirname($error_file)))
        {
            mkdir(dirname($error_file),0777,true);
        }
        file_put_contents($error_file, $error_string.' ['.date('Y-m-d H:i:s').']'.PHP_EOL,FILE_APPEND|LOCK_EX);
        if(stripos($error_file,'Connection timed out')!==false)
        {
            exit ;
        }
    }
}